home *** CD-ROM | disk | FTP | other *** search
- Listing 1. A 256-Color Sprite
- /* ======================================================================== */
- /* COMPLBMP.C - Routine to compile a 256-color bitmap image for */
- /* Mode X or Mode 13h. */
- /* Author: Matt Pritchard for Game Developer Magazine. */
- /* Adapted from MODEX108 */
- /* ======================================================================== */
-
- /* This stuff could go into a .h file */
-
- /* Macro Definitions needed by Compile_Bitmap */
-
- #define ucharf unsigned char far
- #define uchar unsigned char
- #define uint unsigned int
-
- #define hi_word( x ) (unsigned char) (x >> 8)
- #define lo_word( x ) (unsigned char) (x & 0x00FF)
-
- /* Prototypes for Compiled Bitmap Routines */
-
- ucharf * Compile_Bitmap (ucharf *, int, int, int, int);
-
- void far pascal draw_compiled_bitmap (uchar far *, int, ints);
- void far pascal draw_compiled_bitmap_13h (uchar far *, int, ints);
-
- /* ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ*/
-
- /* This function takes a Sprite that is stored in a two-dimensional array, such
- as char ImageData[32][32], and creates a buffer that contains the machine
- language code to quickly draw that image in Mode 13h or Mode X.
-
- The sprite data is stored line by line, from top to bottom. Each line
- is stored from left to right. A transparant color value is used to
- indicate which pixels are not part of the image and should not be drawn.
-
- Because Mode X supports various screen sizes, we must know the width
- of the screen a sprite will be displayed on in advance. For Mode 13h,
- that width is normally 320.
-
- When possible, two adjacent pixels will be drawn with one 16-bit MOV
- instruction. This results in smaller and faster code.
-
- This function allocates a buffer to hold the compiled code and
- returns a far pointer to it. The pointer need only be a char type
- pointer, since our assembly language routine does the actual calling of it.
-
- If the sprite is too big or the program has run out of memory, a null pointer
- is returned, otherwise a pointer to the compiled code is returned.
- */
-
- ucharf * Compile_Bitmap (ucharf * theImage, /* Far Ptr to the Sprite */
- int X_width, /* Width of the Sprite */
- int Y_width, /* Height of the Sprite */
- int Trans_Color, /* Transparent Color */
- int Screen_Width) /* Width of the screen */
- {
-
- int x, y, p; /* Loop counters for X, Y, and plane */
- int Words, Bytes; /* Count of each type of instruction */
- int b1, b2; /* Valid pixel flags */
- uint VidOffset, Offset; /* Offsets for memory calculations */
-
- int BytesPerLine; /* Width of display in address bytes */
- long CompiledBufferSize; /* The size of the compiled sprite code*/
- long c; /* Counter for the code writing loop */
-
- ucharf * theBuffer; /* Pointer to the compiled code buffe */
-
- int Num_Planes; /* The number of video planes (4 or 1)*/
- int Next_Pixel; /* The number of bytes between adjacent pixel*/
- int Code_Overhead; /* Size of any overhead code needed */
-
- /* The variable Mode_X controls if we are compiling a sprite for Mode 13h or
- Mode X. For Mode X, we must split the image into four separate planes and
- add plane switching code to the compiled sprite. If the value of Mode_X is
- 0, we compile for Mode 13h, otherwise we compile for Mode X. */
-
- int Mode_X = -1; /* -1 = Mode X, 0 = Mode 13h */
-
- if (Mode_X) {
- Num_Planes = 4;
- Next_Pixel = 4;
- Code_Overhead = 20;
- } else {
- Num_Planes = 1;
- Next_Pixel = 1;
- Code_Overhead = 5;
- }
-
- BytesPerLine = Screen_Width / Num_Planes;
-
- /* First, we pass through the bitmap and count up the number of adjacent pixel
- pairs and the number of single pixels. With this information, we will know
- how big a buffer to allocate. */
- Words = Bytes = 0;
-
- for (p = 0; p < Num_Planes; p++)
- {
- for (y = 0; y < Y_width; y++)
- {
- Offset = y * X_width;
- for (x = p; x < X_width; x+=Next_Pixel)
- {
- /* Check the current pixel to see if it should be displayed */
-
- b1 = (theImage[Offset+x] != Trans_Color) ? -1 : 0;
-
- /* Check the next adjacent pixel (if there is one), and see if
- it should also be displayed */
-
- if ((x + Next_Pixel) < X_width) {
- b2 = (theImage[Offset+x+Next_Pixel] != Trans_Color) ? -1 : 0;
- } else {
- b2 = 0;
- }
-
- /* Check for a pair of adjacent pixels, or a lone single pixel */
-
- if (b1) {
- if (b2) {
- Words++; /* Another adjacent pixel pair */
- x+=Next_Pixel; /* Skip over the next pixel */
- } else {
- Bytes++; /* One more lone pixel */
- }
- }
- }
- }
- }
-
- /* Determine how big a buffer we need for the compiled code, allocate it, and
- get a far pointer to it. */
- CompiledBufferSize = Code_Overhead + (6 * Words) + (5 * Bytes);
-
- /* Here is where the users can insert their own error handling code */
- if (CompiledBufferSize > 65535) {
- /* Error; compiled sprite would be too large (greater than 64K). */
- return (0);
- }
-
- if ( (theBuffer = (ucharf *) malloc( (size_t) CompiledBufferSize)) == 0) {
- /* Error allocating buffer; out of memory. */
- return (0);
- }
-
- /* Now, we go through the image again, this time creating the code to write into
- the compile code buffer. */
-
- c = 0;
- for (p = 0; p < Num_Planes ; p++)
- {
- for (y = 0; y < Y_width; y++)
- {
- Offset = y * X_width;
- for (x = p; x < X_width; x+=Next_Pixel)
- {
-
- /* Check the current pixel to see if it should be displayed */
-
- b1 = (theImage[Offset+x] != Trans_Color) ? -1 : 0;
-
- /* Check the next adjacent pixel (if there is one), and see if it
- should also be displayed */
-
- if ((x + Next_Pixel) < X_width) {
- b2 = (theImage[Offset+x+Next_Pixel] != Trans_Color) ? -1 : 0;
- } else {
- b2 = 0;
- }
-
- /* Generate code for a pair of pixels, or for a single pixel. */
-
- if (b1) {
- VidOffset = (BytesPerLine * y) + ((x-p) / Num_Planes);
-
- if (b2) { /* Create Code to write Word Constant */
-
- theBuffer[c++] = 0xC7; /* MOV word ptr */
- theBuffer[c++] = 0x87;
- theBuffer[c++] = lo_word( VidOffset ); /* BX+VidOffset */
- theBuffer[c++] = hi_word( VidOffset );
- theBuffer[c++] = (uchar) theImage[Offset+x];
- theBuffer[c++] = (uchar) theImage[Offset+x+Next_Pixel];
-
- x+=Next_Pixel; /* Skip over second pixel*/
-
- } else { /* Create Code to write Byte Constant*/
-
- theBuffer[c++] = 0xC6; /* MOV byte ptr */
- theBuffer[c++] = 0x87;
- theBuffer[c++] = lo_word( VidOffset ); /* BX+VidOffset */
- theBuffer[c++] = hi_word( VidOffset );
- theBuffer[c++] = (uchar) theImage[Offset+x];
- }
- }
- }
- }
-
- if ( (Mode_X) && (p < 3) ) { /* Generate plane switching code*/
-
- theBuffer[c++] = 0xD0; /* ROL AL, 1 ; Get New mask*/
- theBuffer[c++] = 0xC0;
- theBuffer[c++] = 0x13; /* ADC BX, CX ; Add in Addr wrap*/
- theBuffer[c++] = 0xD9;
- theBuffer[c++] = 0xEE; /* OUT DX, AL ; Select new Plane*/
- }
- }
-
- /* Create exit code to return to the calling program */
-
- theBuffer[c++] = 0x5D; /* POP BP ; Restore BP */
- theBuffer[c++] = 0x1F; /* POP DS ; Restore DS */
- theBuffer[c++] = 0xCA; /* RETF 8 ; Exit & Clean Up Stack*/
- theBuffer[c++] = 0x08;
- theBuffer[c++] = 0x00;
-
- /* Return a pointer to the Buffer containing the Compiled Code */
-
- return (theBuffer);
-
- }
- Listing 2. Compiled Sprite Setup and Call Routine
- ; =========================================================;
- ; COMPLBMP.ASM - Compiled Sprite Setup & Call Routines for;
- ; Mode X or Mode 13h. ;
- ; Author; Matt Pritchard for Game Developer Magazine. ;
- ; Adapted from MODEX108 ;
- ; Assembler Used; MASM 5.10a ;
- ; =========================================================;
-
- .MODEL Medium
- .286
- .CODE
-
- ; ===== General Constants & Macros =====
-
- wp EQU WORD PTR
- dp EQU DWORD PTR
- fp EQU FAR PTR
-
- ; ===== VGA Register Values & Constants =====
-
- VGA_Segment EQU 0A000h ;Vga Memory Segment
-
- SC_Index EQU 03C4h ; VGA Sequencer Controller
- SC_Data EQU 03C5h ; VGA Sequencer Data Port
-
- MAP_MASK_PLANE2 EQU 01102h ; Map Register + Plane 1
- PLANE_BITS EQU 03h ; Bits 0-1 of Xpos = Plane#
-
- ;==========================================================
- ; DRAW_COMPILED_BITMAP (CompiledImage, X_pos, Y_Pos)
- ;==========================================================
- ;
- ; Sets up a call to a compiled bitmap in Mode X.
- ;
- ; ENTRY; Image = Far Pointer to Compiled Bitmap Data
- ; Xpos = X position to Place Upper Left pixel at
- ; Ypos = Y position to Place Upper Left pixel at
- ;
- ; EXIT; No meaningful values returned
- ;
-
- DCB_STACK STRUC
- DW ?,? ; DS, BP
- DD ? ; Caller
- DCB_Ypos DW ? ; Y position to Draw Bitmap at
- DCB_Xpos DW ? ; X position to Draw Bitmap at
- DCB_Image DD ? ; Far Pointer to Graphics Bitmap
- DCB_STACK ENDS
-
- PUBLIC DRAW_COMPILED_BITMAP
-
- DRAW_COMPILED_BITMAP PROC FAR
-
- Push DS ; Save DS
- Push BP ; AX-DX are destroyed
- Mov BP, SP ; Set up Stack Frame
-
- ; Get DS;BX to point to (Xpos,Ypos) on the current
- ; display page in VGA memory
-
- ; ***** USER NOTE ***** MODIFY AS NEEDED *****
- ;
- ; Line_Offset is lookup table containing the start
- ; offset for each line in VGA display memory.
- ; Here, I assume it to be a table of word values
- ; which are stored in the current code segment.
-
- Mov BX, [BP].DCB_Ypos ; BX = Ypos
- Add BX, BX ; Scale BX to Word Offset
- Mov BX, wp CS;Line_Offset[BX] ; Get Offset of Line Ypos
-
- Mov AX, [BP].DCB_Xpos ; Get UL Corner Xpos
- Mov CL, AL ; Save Plane # in CL
- Shr AX, 2 ; X/4 = Offset Into Line
- ; ***** USER NOTE ***** MODIFY AS NEEDED *****
- ;
- ; CURRENT PAGE is a DWORD pointer to the currently active
- ; Mode X video memory page. The first word is the offset
- ; into the video adaptor, and the second is the constant
- ; value of A000 - the VGAOs graphics memory segment.
- ; Here, I assume it to be in DGROUP.
-
- Lds DX, dp CURRENT_PAGE ; Get Current VGA Page
- Add BX, DX ; DS;BX->Start of Line
- Add BX, AX ; DS;BX->Upper Left Pixel
-
- ; Select the first video plane, and set up the registers
- ; so the next 3 planes can be quickly selected.
-
- And CL, PLANE_BITS ; CL = Starting Plane #
- Mov AX, MAP_MASK_PLANE2 ; Mask & Plane Select
- Shl AH, CL ; Select correct Plane
- Mov DX, SC_Index ; VGA Sequencer ports
- Out DX, AX ; Set Initial Vid Plane
- Inc DX ; Point DX to SC_Data
- Mov AL, AH ; Mask for future OUTOs
- Clr CX ; CX = Constant 0
-
- ; Setup DS; BX = Upper left corner of Image in VGA memory
- ; BP = Local Stack Frame
- ; AL = OUT mask for Selecting video Plane
- ; CX = Constant value 0 for ADC
- ; DX = SC_Data; VGA Sequencer Data Port
- ; AH = Destroyed
- ; SI,DI = Not modified during call
- ;
- ; Now we jump to the compiled code which actually draws the
- ; sprite. The compiled code will return to the caller.
-
- Jmp dp [BP].DCB_Image ; Draw Sprite
-
- DRAW_COMPILED_BITMAP ENDP
-
-
-
- ;=============================================================
- ; DRAW_COMPILED_BITMAP_13h (CompiledImage, X_pos, Y_Pos)
- ;=============================================================
- ;
- ; Sets up a call to a compiled bitmap in Mode 13h.
- ;
- ; ENTRY; Image = Far Pointer to Compiled Bitmap Data
- ; Xpos = X position to Place Upper Left pixel at
- ; Ypos = Y position to Place Upper Left pixel at
- ;
- ; EXIT; No meaningful values returned
- ;
-
- PUBLIC DRAW_COMPILED_BITMAP_13H
-
- DRAW_COMPILED_BITMAP_13H PROC FAR
-
- Push DS ; Save DS
- Push BP ; AX-DX are destroyed
- Mov BP,, SP ; Set up Stack Frame
-
- ; Get DS;BX to point to (Xpos, Ypos) in VGA memory
-
- ; ***** USER NOTE ***** MODIFY AS NEEDED *****
- ;
- ; Line_Offset is lookup table containing the start
- ; offset for each line in VGA display memory.
- ; Here, I assume it to be a table of word values
- ; which are stored in the current code segment.
-
- Mov BX, [BP].DCB_Ypos ; BX = Ypos
- Add BX, BX ; Scale BX to Word Offset
- Mov BX, wp CS;Line_Offset[BX] ; Get Offset of Line Ypos
- Add BX, BP].DCB_Xpos ; Get UL Corner of Sprite
-
- Mov AX, VGA_Segment ; Segment A000
- Mov DS, AX ; DS;BX -> VGA memory
-
- ; Setup DS; BX = Upper left corner of Image in VGA memory
- ; BP = Local Stack Frame
- ; AX = Destroyed
- ; SI, DI = Not modified during call
- ; CX, DX = Not modified during call
- ;
- ; Now we jump to the compiled code which actually draws the
- ; sprite. The compiled code will return to the caller.
-
- Jmp dp [BP]. DCB_Image ; Draw Sprite
-
- DRAW_COMPILED_BITMAP_13H ENDP
-
- END
-
-